const path = require('path');
const express = require('express');
const { get } = require('lodash');
const fs = require('fs');
const escpos = require('escpos');
const USB = require('escpos-usb');
const Network = require('escpos-network');
const logger = require('./logger');
const { getConfig, sleep } = require('./utils');
const { sendEventToAllClient } = require('./socketio');

const config = getConfig();
let PRINTER;
let DEVICE;

const port = get(config, 'printer.port');
const netIp = get(config, 'printer.netIp');
const netPort = get(config, 'printer.netPort', 9100);
const vendorId = get(config, 'printer.vendorId');
const productId = get(config, 'printer.productId');
const printInterval = get(config, 'printInterval', 400);

if (port === 'USB') {
  // install escpos-usb adapter module manually
  escpos.USB = USB;
}
else if (port === 'NET') {
  escpos.Network = Network;
}

const router = express.Router();

function createDevice() {
  if (!DEVICE) {
    if (port === 'NET') {
      DEVICE = new escpos.Network(netIp, netPort);
    }
    else if (port === 'USB') {
      if (vendorId && productId) {
        DEVICE = new escpos.USB(vendorId, productId);
      }
    }
  }

  if (!DEVICE) {
    DEVICE = new escpos.USB();
  }

  return DEVICE;
}

function getPrinter() {
  if (!PRINTER) {
    const device = createDevice();
    const options = { encoding: 'GB18030' };
    PRINTER = new escpos.Printer(device, options);
  }

  return PRINTER;
}

function printImage(dataUrl) {
  const device = createDevice();
  const printer = getPrinter();

  return new Promise((resolve, reject) => {
    escpos.Image.load(dataUrl, (image) => {
      device.open((error) => {
        if (error) {
          reject(error);
        }
        else {
          printer
            .align('CT')
            .raster(image)
            .feed(2);
          printer.cut().close();
          resolve();
        }
      });
    });
  });
}

function loadImage(dataURI) {
  return new Promise((resolve) => {
    escpos.Image.load(dataURI, (image) => resolve(image));
  });
}

// .align('ct') // 对齐方式 LT=Left CT=Center RT=Right
// .style('NORMAL')
// "NORMAL" | "B" | "I" | "U" | "U2" | "BI" | "BIU" | "BIU2" | "BU"
// | "BU2" | "IU" | "IU2"; B=Bold I=Italic U=Underline U2=双线
function print(data) {
  const device = createDevice();
  const printer = getPrinter();

  return new Promise((resolve, reject) => {
    device.open(async (error) => {
      if (error) {
        return reject(error);
      }

      if (Array.isArray(data) && data.length > 0) {
        for (const item of data) {
          if (item.content === '{fullCut}') {
            printer.cut();
          }
          else if (item.content === '{partCut}') {
            printer.cut(true);
          }
          else if (item.content === '{drawLine}') {
            printer.drawLine();
          }
          else if (item.content === '{newLine}') {
            printer.newLine();
          }
          else if (item.content === '{feed}') {
            printer.feed(1);
          }
          else if (item.content.indexOf('{image|') === 0) {
            const temps = item.content.replace('{', '').replace('}', '').split('|');
            let filepath = temps[1];
            if (fs.existsSync(filepath)) {
              // nothing
            }
            else {
              filepath = path.join(process.cwd(), `public/${filepath}`);
              if (!fs.existsSync(filepath)) {
                filepath = null;
              }
            }

            if (filepath) {
              const base64Image = fs.readFileSync(filepath).toString('base64');
              const dataURI = `data:image/png;base64,${base64Image}`;

              // escpos.Image.load(dataURI, (image) => {
              //   printer
              //     .align('CT')
              //     .raster(image);
              // });

              const image = await loadImage(dataURI);
              printer
                .align(item.text_align || 'CT')
                .raster(image);
            }
          }
          else if (item.contentString && item.contentString.length > 0) {
            if (item.margin_left > 0) {
              printer.marginLeft(item.margin_left);
            }

            printer
              .font(item.font || 'A') // 字体 A / B
              .size(item.text_width, item.text_height) // width, height 1普通大小；2，2倍普通大小
              .align(item.text_align || 'LT')
              .style(item.text_style || 'NORMAL')
              .text(item.contentString);
          }
        }
      }

      printer.close();
      /*  test
      printer
        .font('A')// 字体 A / B
        .size(0, 0) // width, height 1普通大小；2，2倍普通大小
        .align('CT')
        .text('北京临空皇冠假日酒店')
        .text('会员卡消费账单')
        .newLine()
        .align('LT')
        .style('I')
        .text('会员卡号: 13810028614')
        .text('交易类型: 华彩中餐厅消费')
        .text('交易金额: ￥1,456.00')
        .text('余    额: ￥5,544.00')
        .style('U')
        .text('交易时间: 2023-10-13 13:23')
        .text('收 银 员: JASON.WU')
        .newLine()
        .text('会员签字: ')
        .newLine()
        .drawLine()
        .text('打印时间: 2023-10-13 13:25')
        .feed(4);

      printer.cut()
        .close();
       */

      return resolve();
    });
  });
}

router.get('/', (req, res) => {
  res.send('Welcome to NCloud Service');
});

router.get('/api/chat', async (req, res, next) => {
  const { message } = req.query;
  try {
    await sendEventToAllClient('MemberCardUID', { UID: message });
    res.send('ok');
  }
  catch (e) {
    next(e);
  }
});

router.get('/api/hmember-card', async (req, res, next) => {
  console.log('======');
  try {
    await sendEventToAllClient('HMemberCardQRCode', req.query);
    res.send('ok');
  }
  catch (e) {
    next(e);
  }
});

router.post('/print', async (req, res, next) => {
  try {
    const { count } = req.query;
    logger.info(JSON.stringify(req.body));

    for (let i = 0; i < Number(count); i += 1) {
      logger.info(`第${i + 1}次打印`);
      if (req.body.canvas) {
        await printImage(req.body.canvas);
      }
      else {
        await print(req.body);
      }
      await sleep(printInterval);
    }

    res.send({
      errCode: 0
    });
  }
  catch (e) {
    next(e);
  }
});

module.exports = router;
